#include <header.h>


typedef enum{
    DATA = 0,   // 传出数据用
    LOGIN,
    REGISTER,
    CD,
    LS,
    PWD,
    PUT_FILE,
    GET_FILE,
    RM,
    MKDIR
}CmdType;

#define TIRE_LEN 50

static int son[TIRE_LEN][26] = {{0}};

static CmdType cnt[TIRE_LEN];


static int idx = 0;



static void insert(const char* str, int len, CmdType type){
    int ptr = 0;

    for (int i = 0; i < len; ++i) {
        int u = str[i] - 'a';
        // printf("str = %s, ptr = %d u = %d, i = %d\n", str, ptr, u, i);
        if (!son[ptr][u]) {
            son[ptr][u] = ++idx;
        }
        ptr = son[ptr][u];
    }
    cnt[ptr] = type;
}



int query(const char* str, int len) {

    int ptr = 0;
    for(int i = 0; i < len; ++i) {
        int u = str[i] - 'a';
    if(!son[ptr][u]){
        return -1;
    }
        ptr = son[ptr][u];
    }
    return cnt[ptr];
}


void initTire() {
    // -1的补码是全1，所以memset数组所有元素都变成了-1
    memset(cnt, -1, sizeof(cnt));

    insert("data", 4, DATA);
    insert("login", 5, LOGIN);
    insert("register", 8, REGISTER);
    insert("cd", 2, CD);
    insert("ls", 2, LS);
    insert("pwd", 3, PWD);
    insert("putfile", 7, PUT_FILE);
    insert("getfile", 7, GET_FILE);
    insert("rm", 2, RM);
    insert("mkdir", 5, MKDIR);
}



/// @brief 字符串去除首尾空格和换行
/// @param str 
void trim(char *str) {
    int start = 0, end = strlen(str) - 1;

    // 找到第一个非空格和非换行符的位置
    while (isspace(str[start]) || str[start] == '\n')
        start++;

    // 找到最后一个非空格和非换行符的位置
    while (end > start && (isspace(str[end]) || str[end] == '\n'))
        end--;

    // 将字符串前移
    memmove(str, str + start, end - start + 1);

    // 在字符串末尾添加空字符
    str[end - start + 1] = '\0';
}

/**
 * @brief 判断输入是否合法
 * @param parameter 会改变参数内容，最终为合法命令的第二个参数内容
 * @return 合法返回1，非法返回0
*/
int handleCommand(unsigned short *command, char *parameter){

    // 去头尾空格
    trim(parameter);
    int isSingleCmd = query(parameter, strlen(parameter));
    if(isSingleCmd != -1){
        *command = isSingleCmd;
        return 1;
    }

    // 判断输入是否合法
    char cmd[1024] = {0};
    char pass[1024] = {0};

    char *token = strtok(parameter, " ");
    strcpy(cmd, token);

    if(token == NULL){
        return 0;
    }
    
    token = strtok(NULL, " ");
    if(token == NULL){
        return 0;
    }
    strncpy(pass, token, 1024);


    int ret2 = query(cmd, strlen(cmd));
    if(ret2 == -1){
        return 0;
    }

    printf("pass:%s\n", pass);
    strncpy(parameter, pass, 1024);
    *command = ret2;
    return 1;
}

typedef struct users{
   char currentDirectory[256];
}Users;
Users user;

/**
 * @return 目录返回1，文件返回0，无此文件返回-1
*/
int isExistThisFileOrDirectory(const char *path){
   struct stat st;
   stat(path, &st);
   if(S_ISDIR(st.st_mode)){
      // 目录
      return 1;
   }else if(S_ISREG(st.st_mode)){
      // 文件
      return 0;
   }
   // 无此文件
   return -1;
}

/**
 * @brief 根据操作拼接目录,不准在根目录cd ..
 * @return 成功返回1， 失败返回0
*/
int changeDirectory(char *paramater){
   Users userBak;
   strcpy(userBak.currentDirectory, user.currentDirectory);

   if(strchr(paramater, ' ') != NULL){
      printf("有空格\n");
      return 0;
   }
   
   char *token = strtok(paramater, "/");
   while(token != NULL){      
      printf("userbak=%s,token=%s\n", userBak.currentDirectory, token);

      if(strcmp(token, ".") == 0){
         // 本目录，不操作

      }else if(strcmp(token, "..") == 0){
         // 不允许在根目录cd ..
         if(strcmp(userBak.currentDirectory, "root") == 0){
            printf("不允许根目录cd ..\n");
            return 0;
         }
         *strrchr(userBak.currentDirectory, '/') = '\0';

      }else{
         strcat(userBak.currentDirectory, "/");
         strcat(userBak.currentDirectory, token);
      }
      token = strtok(NULL, "/");

   }

   int ret = isExistThisFileOrDirectory(userBak.currentDirectory);

   // 无此目录，不能打开文件
   if(ret == -1 || ret == 0){
      printf("无此文件夹，不能打开文件\n");
      return 0;
   }

   strcpy(user.currentDirectory, userBak.currentDirectory);
   return 1;
}




/**
 * @brief 删除文件
*/
void deleteFile(const char *file){
   unlink(file);
}

/**
 * @brief 判断是.还是..
*/
int isthisOrSuper(char *path){
	return strcmp(path, ".") == 0 || strcmp(path, "..") == 0;
}


/**
 * @brief 文件则直接删除，目录则递归删除目录下的所有文件和目录
*/
void deleteDirectoryRecursion(char *path){
   DIR *dirp = opendir(path);
   char pathname[255];
   struct dirent *direntP; 
   while((direntP = readdir(dirp)) != NULL){
      
      if(isthisOrSuper(direntP->d_name)){
         continue;
      }

      if(direntP->d_type != 4){
         // 拼接目录
         sprintf(pathname, "%s/%s", path, direntP->d_name);
         unlink(pathname);
      }else{
         // 拼接目录
         sprintf(pathname, "%s/%s", path, direntP->d_name);
         deleteDirectoryRecursion(pathname);
      }       
   }       
   rmdir(path);
}




/**
 * @brief 删除文件或目录
 * @return 成功返回1，失败返回0
*/
int deleteOperation(char *paramater){
   if(isthisOrSuper(paramater)){
      printf("不允许在本目录删除本目录和父目录\n");
      return 0;
   }

   char path[1024];
   strcat(path, user.currentDirectory);
   strcat(path, "/");
   strcat(path, paramater);

   // 判断有无此目录，文件
   int ret = isExistThisFileOrDirectory(path);
   if(ret == -1){
      printf("无此文件/文件夹\n");
      return 0;
   }else if(ret == 0){

      // 删文件
      deleteFile(path);
      
   }else{
      // 删目录
      deleteDirectoryRecursion(path);
   }
   return 1;
}